package com.zjl.学习.第06章_块步骤_读操作写.A_ItemReader块读;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.zjl.springbatch.util.OutColour;
import com.zjl.学习.第06章_块步骤_读操作写.User;
import org.springframework.batch.core.*;
import org.springframework.batch.core.configuration.annotation.EnableBatchProcessing;
import org.springframework.batch.core.configuration.annotation.JobBuilderFactory;
import org.springframework.batch.core.configuration.annotation.StepBuilderFactory;
import org.springframework.batch.core.launch.JobLauncher;
import org.springframework.batch.core.launch.support.RunIdIncrementer;
import org.springframework.batch.core.repository.JobExecutionAlreadyRunningException;
import org.springframework.batch.core.repository.JobInstanceAlreadyCompleteException;
import org.springframework.batch.core.repository.JobRestartException;
import org.springframework.batch.core.scope.context.ChunkContext;
import org.springframework.batch.core.step.skip.SkipLimitExceededException;
import org.springframework.batch.core.step.skip.SkipPolicy;
import org.springframework.batch.core.step.tasklet.Tasklet;
import org.springframework.batch.item.*;
import org.springframework.batch.item.database.JdbcCursorItemReader;
import org.springframework.batch.item.database.JdbcPagingItemReader;
import org.springframework.batch.item.database.PagingQueryProvider;
import org.springframework.batch.item.database.builder.JdbcCursorItemReaderBuilder;
import org.springframework.batch.item.database.builder.JdbcPagingItemReaderBuilder;
import org.springframework.batch.item.database.support.SqlPagingQueryProviderFactoryBean;
import org.springframework.batch.item.file.FlatFileItemReader;
import org.springframework.batch.item.file.builder.FlatFileItemReaderBuilder;
import org.springframework.batch.item.json.JacksonJsonObjectReader;
import org.springframework.batch.item.json.JsonItemReader;
import org.springframework.batch.item.json.builder.JsonItemReaderBuilder;
import org.springframework.batch.repeat.RepeatStatus;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.core.io.ClassPathResource;
import org.springframework.jdbc.core.ArgumentPreparedStatementSetter;
import org.springframework.stereotype.Component;

import javax.sql.DataSource;
import java.nio.charset.Charset;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@SpringBootApplication
@EnableBatchProcessing
public class A_Item {
    @Autowired//@EnableBatchProcessing 这个注解帮你从 spring batch 的配置文件中加载了
    private JobLauncher jobLauncher;//Job 启动器
    @Autowired
    private JobBuilderFactory jobBuilderFactory;
    @Autowired
    private StepBuilderFactory stepBuilderFactory;

    @Bean
    public FlatFileItemReader<User> userItemReader(){
        return new FlatFileItemReaderBuilder<User>()
                .name("userItemReader")
                .resource(new ClassPathResource("item/user.txt"))  //指定读取的文件
                .delimited().delimiter("#")  //读取出一行数据，该如何分割数据，默认以,分割，当前使用#号分割
                .names("id", "name", "age")//给分割后数据打name标记，后续跟User对象属性进行映射
                .targetType(User.class)      //读取出一行数据封装成什么对象
                .build();
    }

    @Autowired
    private MyFieldSetMapper myFieldSetMapper;

    @Bean
    public FlatFileItemReader<User> userItemReader字段映射(){
        FlatFileItemReader<User> build = new FlatFileItemReaderBuilder<User>()
                .name("userItemReader字段映射")
                .resource(new ClassPathResource("item/user2.txt"))
                .delimited().delimiter("#")
                .names("id", "name", "age", "province", "city", "area")
                .fieldSetMapper(myFieldSetMapper)
                .build();
        return build;
    }
    public ItemReader<User> ItemReader(){
        return new ItemReader<User>() {

            @Override
            public User read() throws Exception, UnexpectedInputException, ParseException, NonTransientResourceException {
                if(true) throw new Exception("xxx");
                return null;
            }
        };
    }
    @Bean
    public JsonItemReader<User> userItemReaderJson读取(){

        ObjectMapper objectMapper = new ObjectMapper();
        JacksonJsonObjectReader<User> jsonObjectReader = new JacksonJsonObjectReader<>(User.class);
        jsonObjectReader.setMapper(objectMapper);

        JsonItemReader<User> userItemReaderJson读取 = new JsonItemReaderBuilder<User>()
                .name("userItemReaderJson读取")
                .jsonObjectReader(jsonObjectReader)
                .resource(new ClassPathResource("item/user.json"))
                .build();
        return userItemReaderJson读取;
    }
    @Autowired
    private DataSource dataSource;//数据源

    @Autowired
    private MyUserRowMapper myUserRowMapper;

    @Bean
    public JdbcCursorItemReader<User> userItemReaderSql(){

        JdbcCursorItemReader<User> userCursorItemReaderSql = new JdbcCursorItemReaderBuilder<User>()
                .name("userCursorItemReaderSql")
                .dataSource(dataSource)
                .sql("select * from employee where id < ?")
                .preparedStatementSetter(new ArgumentPreparedStatementSetter(new Object[]{16}))//添加变量
                .rowMapper(myUserRowMapper)
                .build();
        return userCursorItemReaderSql;
    }
    @Bean
    public PagingQueryProvider pagingQueryProvider() throws Exception {
        SqlPagingQueryProviderFactoryBean factoryBean = new SqlPagingQueryProviderFactoryBean();
        factoryBean.setDataSource(dataSource);
        factoryBean.setSelectClause("select *");   //查询列
        factoryBean.setFromClause("from employee");    //查询的表
        factoryBean.setWhereClause("where age >= :age"); //where 条件
        factoryBean.setSortKey("id");   //结果排序
        return factoryBean.getObject();
    }
    @Bean
    public JdbcPagingItemReader<User> userItemReaderSql分页() throws Exception {
        Map<String, Object> param = new HashMap<>();
        param.put("age", 5);
        JdbcPagingItemReader<User> userPagingItemReader = new JdbcPagingItemReaderBuilder<User>()
                .name("userPagingItemReader")
                .dataSource(dataSource)  //数据源
                .queryProvider(pagingQueryProvider())  //分页逻辑
                .parameterValues(param)   //条件
                .pageSize(2) //每页显示条数  表面看并没啥用，因为每次的数量只控制在   shep 的chunk(2) 的个数中，与此值无关
                .rowMapper(myUserRowMapper)  //映射规则
                .build();

        return userPagingItemReader;
    }
    @Bean//加注解会每次都会抛错，因为Bean在启动时就会执行
    public FlatFileItemReader<User> ItemReadError() throws Exception {
            return new FlatFileItemReaderBuilder<User>()
                    .name("userItemReader")
                    .resource(new ClassPathResource("item/userxxx.txt"))  //指定读取的文件
                    .delimited().delimiter("#")  //读取出一行数据，该如何分割数据，默认以,分割，当前使用#号分割
                    .names("id", "name", "age")//给分割后数据打name标记，后续跟User对象属性进行映射
                    .targetType(User.class)      //读取出一行数据封装成什么对象
                    .build();
        }

    @Bean
    public ItemWriter<User> itemWriter(){
        return new ItemWriter<User>() {
            @Override
            public void write(List<? extends User> items) throws Exception {
                OutColour.out.printlnRed(items + "个数：" + items.size());
            }
        };
    }
    @Bean//任务 Tasklet 这是最简单的    还有Chunk块处理
    public Tasklet tasklet05A(){
        return new Tasklet() {
            @Override
            public RepeatStatus execute(StepContribution contribution, ChunkContext chunkContext) throws Exception {
                StepExecution stepExecution = chunkContext.getStepContext().getStepExecution();
                ExecutionContext executionContext = chunkContext.getStepContext().getStepExecution().getExecutionContext();
                executionContext.put("xx","xx");//放入shep的共享变量

                if(true) throw new Exception("测试");

                chunkContext.getStepContext().getStepExecution().setTerminateOnly();//设置 此操作状态为   STOPPED  //表示已完成的加工 中断状态停止
                OutColour.out.printlnRed("****************A*******************");
                return RepeatStatus.FINISHED;//已完成
            }
        };
    }
    @Autowired
    MyItemReadListener<User> myItemReadListener;//块 读的监听
    @Bean
    public Step stepItem() throws Exception {
        return stepBuilderFactory.get("stepItem")
                .<User, User>chunk(2)//由于每次读取都是一个数据，所以此值表示的是每次读多少条，
                .reader(userItemReader())
                .reader(userItemReader字段映射())
                .reader(userItemReaderJson读取())
                .reader(userItemReaderSql())
                .reader(userItemReaderSql分页())
                .writer(itemWriter())

                .faultTolerant() // 配置错误容忍
                .retry(Exception.class) // 配置重试的异常类型
                .retryLimit(3) // 重试3次，三次过后还是异常的话，则任务会结束，

                .build();

    }
    @Bean
    public Step stepItemError1() throws Exception {
        return stepBuilderFactory
                .get("stepItemError1")
//                .listener(myItemReadListener)
//                .tasklet(tasklet05A())
                .<User, User>chunk(1)//由于每次读取都是一个数据，所以此值表示的是每次读多少条，

                .reader(ItemReadError())
                .reader(ItemReader())
                .writer(itemWriter())

                .faultTolerant() // 配置错误容忍
                .retry(Throwable.class) // 配置重试的异常类型
                .retryLimit(3) // 重试3次，三次过后还是异常的话，则任务会结束，

                .listener(myItemReadListener)
                .listener(new MySkipListener<User, User>())
                .build();
    }

    @Bean
    public Step stepItemError2() throws Exception {
        return stepBuilderFactory.get("stepItemError2")
                .<User, User>chunk(1)//由于每次读取都是一个数据，所以此值表示的是每次读多少条，
                .reader((ItemReader<? extends User>) ItemReadError())
                .writer(itemWriter())
                //异常的判断
                .faultTolerant() //容错
                .skip(NullPointerException.class)  //跳过啥异常
                .noSkip(RuntimeException.class)  //不能跳过啥异常
                .skipLimit(10)  //跳过异常次数
                .skipPolicy(new SkipPolicy() {
                    @Override
                    public boolean shouldSkip(Throwable t, int skipCount) throws SkipLimitExceededException {
                        //定制跳过异常与异常次数
                        return false;
                    }
                })
                .build();
    }
    @Bean
    public Job jobItem() throws Exception {
        return jobBuilderFactory.get("jobItem4")
                .start(stepItemError2())
                .start(stepItemError1())
                .start(stepItem())
                .incrementer(new RunIdIncrementer())
                .build();
    }
    public static void main(String[] args) {
        System.setProperty("spring.profiles.active","01");//  同理 --spring.profiles.active=xxx
        SpringApplication.run(A_Item.class, args);
        System.out.println("***********启动完毕**当前编码:" + Charset.defaultCharset().name() + "****************");

    }
}

